home *** CD-ROM | disk | FTP | other *** search
- /*
- * Blob Manager Demonstration: Pong hau k'i module
- *
- * This is an oriental game played on a 5-position board. Each player
- * has 2 pieces, and the goal is to position to pieces so that the
- * other player cannot move. Pieces may be moved onto the empty
- * position only if the two are connected by a line.
- *
- * * *
- * |\ / |
- * | * |
- * |/ \ |
- * *-----*
- *
- * Since it's so simple, the game gives no feedback. You simply
- * cannot move if the game is over. The reset "button" can be
- * used to start over when the game has been completed.
- *
- * 5 August 1986 Paul DuBois
- */
-
- # include "TransSkel.h"
-
- # include "BlobMgr.h"
- # include "BlobDemo.h"
-
-
- # define pieceSize 20 /* size of each piece */
- # define hOff 15 /* top left corner of playing area */
- # define vOff 20
- # define hSize 80 /* size of playing area */
- # define vSize 60
- # define vMesg 100
-
-
- static WindowPtr wind;
-
- static BlobSetHandle boardBlobs = nil;
- static BlobHandle board[5];
- static BlobSetHandle donors = nil;
- static BlobHandle current;
- static BlobHandle previous;
- static BlobSetHandle misc;
- static BlobHandle resetBlob; /* simulated control */
- static Str255 statusStr;
- static BlobHandle statusBlob;
-
-
- /*
- * Define center points of each position
- */
-
- static Point intersection[5] =
- {
- { vOff, hOff },
- { vOff, hOff + hSize },
- { vOff + vSize/2, hOff + hSize/2 },
- { vOff + vSize, hOff },
- { vOff + vSize, hOff + hSize }
- };
-
- /*
- * Define connections between positions
- */
-
- static Boolean connected[5][5] =
- {
- { false, false, true, true, false },
- { false, false, true, false, true },
- { true, true, false, true, true },
- { true, false, true, false, true },
- { false, true, true, true, false }
- };
-
-
- static void
- StatusMesg (StringPtr s, BlobHandle b)
- {
- Rect r;
-
- SetRect (&r, 0, vMesg, 55, vMesg + 20);
- TextBox (s+1, (long) s[0], &r, teJustRight);
- GlueGlob (b, GetBlobHandle (misc, 0));
- StrCpy (statusStr, s);
- statusBlob = b;
- }
-
-
- /*
- * The donor set consists of two blobs, each filled with a different
- * pattern
- */
-
- static void
- MakeDonors (void)
- {
- BlobHandle b;
- Rect r;
- RgnHandle rgn;
- Pattern p;
- short i;
-
- donors = NewBlobSet ();
- for (i = 9; i <= 16; i += 7) /* use patterns 9, 16 */
- {
- rgn = NewRgn ();
- OpenRgn ();
- SetRect (&r, 0, 0, pieceSize, pieceSize);
- FrameOval (&r);
- CloseRgn (rgn);
-
- b = NewBlob (donors, true, infiniteGlue, false, 0L);
- OpenBlob ();
- GetIndPattern (p, sysPatListID, i);
- FillOval (&r, p);
- FrameOval (&r);
- CloseRgnBlob (b, rgn, rgn);
- DisposeRgn (rgn);
- }
- }
-
-
- static BlobHandle
- MakeReceptor (BlobSetHandle bSet, short h, short v)
- {
- BlobHandle b;
- Rect r;
- RgnHandle rgn;
-
- SetRect (&r, h, v, h + pieceSize, v + pieceSize);
- rgn = NewRgn ();
- OpenRgn ();
- FrameOval (&r);
- CloseRgn (rgn);
-
- b = NewBlob (bSet, true, 0, false, 0L);
- OpenBlob ();
- EraseOval (&r);
- FrameOval (&r);
- CloseRgnBlob (b, rgn, rgn);
- DisposeRgn (rgn);
- return (b);
- }
-
-
- static void
- MakeBoard (void)
- {
- short i;
- Rect r;
-
- boardBlobs = NewBlobSet ();
- for (i = 0; i < 5; i++)
- {
- board[i] = MakeReceptor (boardBlobs,
- intersection[i].h - pieceSize/2,
- intersection[i].v - pieceSize/2);
- }
-
- misc = NewBlobSet ();
- (void) MakeReceptor (misc, 60, vMesg - 2);
- SetRect (&r, 0, 0, 20, 90);
- OffsetRect (&r, wind->portRect.right - 25, 5);
- resetBlob = NewVButtonBlob (misc, &r, "\pReset", true);
- }
-
-
- /*
- * Set the board to the initial configuration
- */
-
- static void
- Reset (void)
- {
- short i;
-
- UnglueGlobSet (boardBlobs); /* clear all globs */
- GlueGlob (GetBlobHandle (donors, 0), board[0]);
- GlueGlob (GetBlobHandle (donors, 0), board[1]);
- GlueGlob (GetBlobHandle (donors, 1), board[3]);
- GlueGlob (GetBlobHandle (donors, 1), board[4]);
- current = FirstBlob (donors);
- previous = NextBlob (current);
- StatusMesg ("\pMove:", current);
- HiliteBlob (resetBlob, inDragBlob, dimDraw);
- }
-
-
- /*
- * Given a blob handle, find the board position that corresponds to it.
- */
-
- static short
- BoardPos (BlobHandle b)
- {
- short i;
-
- for (i = 0; i < 5; ++i)
- {
- if (board[i] == b)
- return (i);
- }
- /* shouldn't ever get here */
- }
-
-
- /*
- * Test whether a piece can move or not. This is true only if
- * the current position is connected to the empty position (of which
- * there is only one).
- */
-
- static Boolean
- CanMove (short n)
- {
- short i;
-
- for (i = 0; i < 5; ++i)
- {
- if (i != n && connected [i][n] && BGlob (board[i]) == nil)
- return (true);
- }
- return (false);
- }
-
-
- /*
- * See whether the game is over or not. It's over if no piece
- * of the current player can move.
- */
-
- static Boolean
- GameOver (void)
- {
- short i;
-
- for (i = 0; i < 5; ++i)
- {
- if (BGlob (board[i]) == current && CanMove (i))
- return (false);
- }
- return (true);
- }
-
-
- /*
- * When a piece is clicked on, the advisory checks whether the piece
- * belongs to the correct player and whether the piece has
- * any legal moves available to it. If so, it returns true, so that
- * BlobClick is allowed to drag the piece. After the piece has been
- * dragged, the advisory checks whether the position it was dragged to
- * is legal (connected to original position), and returns true if so.
- *
- * Messages passed to the advisory follow the pattern
- *
- * { { advRClick advRClick* } advXfer* }*
- *
- * where * means 0 or more instances of the thing *'ed. In particular,
- * the advXfer message is never seen without a preceding advRClick.
- */
-
- static pascal Boolean
- Advisory (short mesg, BlobHandle b)
- {
- static short n; /* static to save board position of click on piece */
-
- switch (mesg)
- {
-
- case advRClick: /* first click on piece */
-
- if (BGlob (b) != current)
- return (false); /* can only move current piece(s) */
- n = BoardPos (b); /* find where it is */
- return (CanMove (n));
-
- case advXfer: /* Mouse released after dragging piece */
-
- return (connected [n][BoardPos (b)]);
- }
- }
-
-
-
- static pascal void
- Mouse (Point pt, long t, short mods)
- {
- BlobHandle b;
- short i;
-
- if (TestBlob (resetBlob, pt) == inDragBlob)
- {
- if (BTrackMouse (resetBlob, pt, inFullBlob))
- Reset ();
- }
- else
- {
- BlobClick (pt, t, nil, boardBlobs);
- if (BClickResult () == bcXfer)
- {
- b = current; /* switch player */
- current = previous;
- previous = b;
- if (GameOver ()) /* see if board is locked */
- {
- StatusMesg ("\pWins:", previous);
- HiliteBlob (resetBlob, inDragBlob, normalDraw);
- }
- else
- StatusMesg ("\pMove:", current);
- }
- }
- }
-
-
- static pascal void
- Update (Boolean resized)
- {
- MoveTo (intersection[3].h, intersection[3].v); /* draw board */
- LineTo (intersection[0].h, intersection[0].v);
- LineTo (intersection[4].h, intersection[4].v);
- LineTo (intersection[1].h, intersection[1].v);
- LineTo (intersection[3].h, intersection[3].v);
- LineTo (intersection[4].h, intersection[4].v);
- DrawBlobSet (boardBlobs);
- DrawBlobSet (misc);
- StatusMesg (statusStr, statusBlob);
- }
-
-
- /*
- * Activate the window: Set the advisory function and set the permissions
- * to transfer-only. Clear, replace, duplication and swap are off.
- * Since replace is off, the advisory doesn't have to check whether
- * the dragged piece was dragged onto a blob that already has a glob.
- *
- * Deactivate the window: Clear the advisory.
- */
-
- static pascal void
- Activate (Boolean active)
- {
-
- if (active)
- {
- SetDragRects (wind);
- SetBCPermissions (false, true, false, false, false); /* xfer only */
- SetBCAdvisory (Advisory);
- }
- else
- {
- SetBCAdvisory (nil);
- }
- }
-
-
- void
- PongInit (void)
- {
- SkelWindow (wind = GetDemoWind (pongWindRes),
- Mouse, /* mouse clicks */
- nil, /* key clicks */
- Update, /* updates */
- Activate, /* activate/deactivate events */
- nil, /* close window */
- DoWClobber, /* dispose of window */
- nil, /* idle proc */
- false); /* irrelevant, since no idle proc */
-
- MakeDonors ();
- MakeBoard ();
- Reset ();
-
- MakeFrontWind (wind);
- }
-